package services

import (
	"GOPAAS/internal/app/global"
	"GOPAAS/internal/app/model"
	"database/sql"
	"errors"
	"gorm.io/gorm"
	"time"
)

type CronService struct {
	model.IrCron
}

func GetCronService(id int64) *CronService {
	var Cron model.IrCron
	if id > 0 {
		db.First(&Cron, id)
	}
	return &CronService{Cron}
}

type CronItem struct {
	Id             int64  `json:"id"`
	Name           string `json:"name"`
	Priority       int    `json:"priority"`
	ModelId        string `json:"model_id"`
	NextCall       string `json:"nextcall"`
	IntervalNumber int    `json:"interval_number"`
	IntervalType   string `json:"interval_type"`
	NumberCall     int    `json:"numbercall"`
	Active         bool   `json:"active"`
	CreateDate     string `json:"create_date"`
}

// GetList 调度器列表
func (c *CronService) GetList(start int, length int, order string, sort string, name string, active sql.NullBool, model_id int64, create_date_b string, create_date_e string, ids []int64) (res []CronItem, total int64, err error) {
	db = getDB()
	res = make([]CronItem, 0)
	data_query := db.Model(&model.IrCron{}).Joins("left join ir_act_server on ir_cron.ir_actions_server_id=ir_act_server.id")
	count_query := db.Model(&model.IrCron{}).Joins("left join ir_act_server on ir_cron.ir_actions_server_id=ir_act_server.id")
	if name != "" {
		data_query.Where("ir_cron.cron_name like ?", "%"+name+"%")
		count_query.Where("ir_cron.cron_name like ?", "%"+name+"%")
	}
	if active.Valid {
		data_query.Where("ir_cron.active = ?", active.Bool)
		count_query.Where("ir_cron.active = ?", active.Bool)
	}
	if model_id > 0 {
		data_query.Where("ir_act_server.model_id = ?", model_id)
		count_query.Where("ir_act_server.model_id = ?", model_id)
	}
	if create_date_b != "" && create_date_e != "" {
		create_date_b = create_date_b + " 00:00:00"
		create_date_e = create_date_e + " 23:59:59"
		data_query.Where("ir_cron.create_date between ? and ?", create_date_b, create_date_e)
		count_query.Where("ir_cron.create_date between ? and ?", create_date_b, create_date_e)
	}
	if len(ids) > 0 {
		data_query.Where("ir_cron.id in ?", ids)
		count_query.Where("ir_cron.id in ?", ids)
	}
	switch order {
	case "model_id":
		order = "ir_act_server." + order
	default:
		order = "ir_cron." + order
	}
	var app_str = order + " " + sort
	type JoinModel struct {
		model.IrCron
		ModelId   int64
		Model     model.IrModel
		ModelName string
	}
	var result []JoinModel
	count_query.Count(&total)
	data_query.Preload("Model").Select("ir_cron.*", "ir_act_server.model_id").Offset(start).Limit(length).Order(app_str).Find(&result)
	for _, v := range result {
		res = append(res, CronItem{
			Id:             v.Id,
			Name:           v.CronName,
			Priority:       int(v.Priority.Int64),
			ModelId:        v.Model.Name,
			NextCall:       v.NextCall.Format("2006-01-02 15:04:05"),
			IntervalNumber: int(v.IntervalNumber.Int64),
			IntervalType:   v.IntervalType.String,
			NumberCall:     int(v.NumberCall.Int64),
			Active:         v.Active,
			CreateDate:     v.CreateDate.Format("2006-01-02 15:04:05"),
		})
	}
	return
}

// RemoveCron 删除调度器
func (c *CronService) RemoveCron() error {
	db = getDB()
	var Cron = c.IrCron
	res := db.Delete(&Cron)
	return res.Error
}

// RemoveCrones 批量删除调度器
func RemoveCrones(cron_id_arr []int64) error {
	db = getDB()
	var Cron model.IrCron
	res := db.Delete(&Cron, cron_id_arr)
	return res.Error
}

// CreateCron 创建调度器
func CreateCron(info global.CreateCronRequest, login_user_id int64) (u_id int64, err error) {
	db = getDB()
	var cron model.IrCron
	db.Where("cron_name = ?", info.Name).First(&cron)
	if cron.Id > 0 {
		err = errors.New("名称已存在")
		return
	}
	server := model.IrActServer{
		Name:             info.Name,
		ModelId:          info.ModelId,
		ModelName:        info.ModelName,
		WebsitePublished: info.WebsitePublished,
		ResCommon: model.ResCommon{
			CreateUid: login_user_id,
			WriteUid:  login_user_id,
		},
	}
	tx := db.Begin()
	var result *gorm.DB
	result = tx.Select("Name", "ModelId", "ModelName", "BindingType", "BindingViewTypes", "Usage", "State", "Sequence", "WebsitePublished", "CreateUid", "WriteUid").Create(&server)
	if result.Error != nil {
		err = result.Error
		tx.Rollback()
		return
	}
	cron = model.IrCron{
		IrActionsServerId: server.Id,
		CronName:          info.Name,
		UserId:            info.UserId,
		Active:            info.Active,
		IntervalNumber:    info.IntervalNumber,
		IntervalType:      info.IntervalType,
		NextCall:          info.NextCall,
		NumberCall:        info.NumberCall,
		Priority:          info.Priority,
		DoAll:             info.DoAll,
		ResCommon: model.ResCommon{
			CreateUid: login_user_id,
			WriteUid:  login_user_id,
		},
	}
	result = tx.Select("CronName", "IrActionsServerId", "UserId", "Active", "IntervalNumber", "IntervalType", "NextCall", "NumberCall", "Priority", "DoAll", "CreateUid", "WriteUid").Create(&cron) // 通过数据的指针来创建
	if result.Error != nil {
		err = result.Error
		tx.Rollback()
		return
	}
	tx.Commit()
	u_id = cron.Id
	return
}

// UpdateCron 修改任务
func (c *CronService) UpdateCron(info global.CreateCronRequest, login_user_id int64) (err error) {
	db = getDB()
	var cron model.IrCron
	db.Where("cron_name = ?", info.Name).Where("id <>?", c.Id).First(&cron)
	if cron.Id > 0 {
		err = errors.New("名称已存在")
		return
	}
	server := model.IrActServer{
		Name:             info.Name,
		ModelId:          info.ModelId,
		ModelName:        info.ModelName,
		WebsitePublished: info.WebsitePublished,
		ResCommon: model.ResCommon{
			Id:       c.IrActionsServerId,
			WriteUid: login_user_id,
		},
	}
	tx := db.Begin()
	var result *gorm.DB
	result = tx.Select("Name", "ModelId", "ModelName", "WebsitePublished", "WriteUid").Save(&server)
	if result.Error != nil {
		err = result.Error
		tx.Rollback()
		return
	}
	cron = model.IrCron{
		IrActionsServerId: server.Id,
		CronName:          info.Name,
		UserId:            info.UserId,
		Active:            info.Active,
		IntervalNumber:    info.IntervalNumber,
		IntervalType:      info.IntervalType,
		NextCall:          info.NextCall,
		NumberCall:        info.NumberCall,
		Priority:          info.Priority,
		DoAll:             info.DoAll,
		ResCommon: model.ResCommon{
			Id:       c.Id,
			WriteUid: login_user_id,
		},
	}
	result = tx.Select("CronName", "IrActionsServerId", "UserId", "Active", "IntervalNumber", "NumberCall", "IntervalType", "NextCall", "Priority", "DoAll", "WriteUid").Save(&cron)
	if result.Error != nil {
		err = result.Error
		tx.Rollback()
		return
	}
	tx.Commit()
	return
}

// ChangeActiveCron 关闭/启用任务
func (c *CronService) ChangeActiveCron(active bool, login_user_id int64) (err error) {
	c.Active = active
	c.WriteUid = login_user_id
	db.Save(&c.IrCron)
	return
}

type CronInfo struct {
	model.IrCron
	ModelId          int64
	ModelName        string
	Author           string
	NextDateTime     string
	WebsitePublished bool
}

// GetCronInfo 获取调度器信息
func (c *CronService) GetCronInfo() (result CronInfo) {
	db = getDB()
	var cron model.IrCron
	db.Preload("User").Preload("User.Partner").Preload("IrActServer").First(&cron, c.Id)
	result = CronInfo{
		IrCron:           cron,
		ModelId:          cron.IrActServer.ModelId,
		ModelName:        cron.IrActServer.ModelName,
		Author:           cron.User.Partner.Name,
		NextDateTime:     cron.NextCall.Format("2006-01-02 15:04:05"),
		WebsitePublished: cron.IrActServer.WebsitePublished.Bool,
	}
	return
}

// GetActiveCrones 获取所有的调度器
func GetActiveCrones() []model.IrCron {
	db = getDB()
	var crones []model.IrCron
	db.Where("active=?", true).Where("id=?", 43).Order("priority desc").Find(&crones)
	return crones
}

// DecreaseCron 执行完任务更新
func (c *CronService) DecreaseCron() (err error) {
	db = getDB()
	if c.NumberCall.Int64 > 0 {
		c.NumberCall.Int64--
	}
	if !c.NumberCall.Valid {
		c.NumberCall.Int64 = 0
		c.NumberCall.Valid = true
	}
	if c.IntervalNumber.Int64 > 0 {
		switch c.IntervalType.String {
		case "minutes":
			c.NextCall = time.Now().Add(time.Minute * time.Duration(c.IntervalNumber.Int64))
		case "hours":
			c.NextCall = time.Now().Add(time.Hour * time.Duration(c.IntervalNumber.Int64))
		case "days":
			c.NextCall = time.Now().AddDate(0, 0, int(c.IntervalNumber.Int64))
		case "weeks":
			c.NextCall = time.Now().Add(time.Hour * 24 * 7 * time.Duration(c.IntervalNumber.Int64))
		case "months":
			c.NextCall = time.Now().AddDate(0, int(c.IntervalNumber.Int64), 0)
		}
	}
	db.Save(&c.IrCron)
	return
}
